﻿/**************************************************************************************
 * CrmDotNetCodeMigrator
 * Tools to assist the Dynamics CRM developer when moving their code from
 * CRM 4.0 to CRM 2011.
 *
 * @copyright    Copyright (c) 2013, CRM Accelerators (http://www.crmaccelerators.net)
 * @license      Microsoft Public License (Ms-PL)
 * @developer    Mitch Milam (http://blogs.infinite-x.net)
 * @version      1.0
 *
 * THIS SOFTWARE IS PROVIDED BY CRM Accelerators ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL CRM Accelerators BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **************************************************************************************/

using System;
using System.IO;
using System.Text;
using CrmDotNetCodeMigrator;
using CommandLine;

namespace CreateVisualStudioMacros
{
    class Program
    {
        private static string OutputFolder { get; set; }
        private static string CrmServerUrl { get; set; }
        private static string UserName { get; set; }
        private static string Password { get; set; }
        private static string DomainName { get; set; }
        private static ConnectionTypes ConnectionType { get; set; }

        static void Main(string[] args)
        {
            var options = new CommandLineOptions();

            if (!Parser.Default.ParseArguments(args, options))
            {
                return;
            }
            
            OutputFolder = options.OutputFolder;
            CrmServerUrl = options.CrmServerUrl;
            UserName = options.UserName;
            Password = options.Password;
            DomainName = options.DomainName;
            ConnectionType = (ConnectionTypes) options.ConnectionType;

            if (options.Verbose)
            {
                // Console.WriteLine("Filename: {0}", options.InputFile);
            }

            Utility.UpdateStatus("Connecting to CRM and retrieving metadata...", false);

            var crm2011 = new Crm2011(CrmServerUrl, UserName, Password, DomainName, ConnectionType);

            CheckEntityList(crm2011);

            Utility.UpdateStatus(" Done.", true);

            CreateOutputFolder(OutputFolder);

            BuildReplaceLogicalNamesMacro(crm2011, OutputFolder);
            BuildAttributeMacros(crm2011, OutputFolder);

            DisplayCompletion();
        }

        private static void DisplayCompletion()
        {
            Utility.UpdateStatus("\r\n\r\nOperation complete.  Press any key to continue.", true);

            Console.ReadKey();
        }

        private static void CreateOutputFolder(string outputFolder)
        {
            if (!Directory.Exists(outputFolder))
            {
                Directory.CreateDirectory(outputFolder);
            }
        }

        private static void BuildReplaceLogicalNamesMacro(Crm2011 crm2011, string folderName)
        {
            Utility.UpdateStatus("Creating LogicalNames Macro...", false);

            const string logicalNameMacro = "\tMySearchReplace(\"EntityName.{0}.ToString()\", \"{1}.EntityLogicalName\", False, False)\r\n";

            var sb = new StringBuilder();

            sb.AppendLine("Public Sub ReplaceEntityLogicalNames()");

            foreach (var entity in crm2011.EntityList)
            {
                sb.AppendFormat(logicalNameMacro, entity.LogicalName, entity.SchemaName);
            }

            sb.AppendLine("End Sub");

            Utility.WriteToFile(Path.Combine(folderName, "LogicalNames.vb"), sb);

            Utility.UpdateStatus(" Done.", true);
        }

        private static void BuildAttributeMacros(Crm2011 crm2011, string folderName)
        {
            //var macro2 = "\tMySearchReplace(\"{0}\", \"{1}\", True, False)\r\n";
            const string macroTemplate = "\tMySearchReplace(\".{0}\", \".{1}\", True, False)\r\n";

            foreach (var entity in crm2011.EntityList)
            {
                Utility.UpdateStatus(string.Format("Creating attribute name replacement macro: {0}...", entity.LogicalName), false);

                var attributeList = crm2011.BuildAttributeList(entity.LogicalName);

                if (attributeList.Count == 0)
                {
                    Utility.UpdateStatus(" No attributes found.", true);

                    continue;
                }

                var sb = new StringBuilder();

                sb.AppendFormat("Public Sub ReplaceAttributeNamesFor{0}()\r\n", entity.SchemaName);

                foreach (var attribute in attributeList)
                {
                    sb.AppendFormat(macroTemplate, attribute.LogicalName, attribute.SchemaName);
                }

                sb.AppendLine("End Sub\r\n");

                var fileName = Path.Combine(folderName, string.Format("ReplaceAttributeNames-{0}.vb", entity.LogicalName));

                Utility.WriteToFile(fileName, sb);

                Utility.UpdateStatus(" Done.", true);
            }
        }

        private static void CheckEntityList(Crm2011 crm2011)
        {
            if (crm2011 == null)
            {
                throw new ArgumentNullException("crm2011");
            }

            if (crm2011.EntityList == null ||
                crm2011.EntityList.Count == 0)
            {
                throw new NullReferenceException("EntityList is empty.");
            }
        }
    }
}
